﻿using Autofac.Core;
using Core.Extension;
using Lextm.SharpSnmpLib;
using Newtonsoft.Json.Linq;
using PacketDotNet;
using PacketDotNet.Utils;
using SharpPcap;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace Services.Equ.PcapCommunication.Abstract
{
    /// <summary>
    /// 抽象Pcap操作通讯类 每一个Pcap操作都可以继承本类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class AbstractPcapCommunication<T>
    {
        /// <summary>
        /// 目标设备mac地址
        /// </summary>
        public PhysicalAddress DestinationMac { get; private set; }
        /// <summary>
        /// 通信密码
        /// </summary>
        public string Password { get; private set; }
        /// <summary>
        /// 通信设备
        /// </summary>
        public ILiveDevice Device { get; private set; }
        /// <summary>
        /// 收到多少条报文之后立即跳出等待
        /// </summary>
        public int ReciveBreak { get; set; } = 100;
        /// <summary>
        /// 最长等待时间
        /// </summary>
        public int WaitMillisecond { get; set; } = 3000;
        /// <summary>
        /// 是否自动操作网卡的打开与关闭（批量操作时必须手动控制网卡的开关）
        /// </summary>
        public bool IsAutoControlDevice { get; set; } = true;
        public byte[] CustomerType { get; protected set; } = [0xf1, 0xf1];
        public int OperationId { get; protected set; } = 12345678;//55058167;
        public byte[] Frame { get; protected set; } = [255, 1];
        /// <summary>
        /// 操作顺序
        /// </summary>
        public int SeqId { get; set; } = 0;
        public int DcpType { get; protected set; } = 0x10001;
        public int OptionType { get; protected set; } = 0;
        public short Version { get; protected set; } = 0;
        public short RpcType { get; protected set; } = 0;
        public short OpType { get; protected set; } = 0;
        public short RESL { get; protected set; } = 0;
        public byte[] UUID { get; set; } = Guid.NewGuid().ToByteArray(); /*[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];*/
        public byte FrgFlg { get; protected set; } = 0;
        public byte LastFrgElg { get; protected set; } = 0;
        public byte NoFackFlg { get; protected set; } = 0;
        public byte RES2 { get; protected set; } = 0;
        public int FrqNum { get; protected set; } = 0;
        public int Status { get; protected set; } = 0;
        public byte[] Res3 { get; protected set; } = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="destinationMac">目标设备mac地址</param>
        /// <param name="password">通信密码</param>
        /// <param name="device">通信设备</param>
        public AbstractPcapCommunication(PhysicalAddress destinationMac, string password, ILiveDevice device)
        {
            DestinationMac = destinationMac;
            Password = password;
            Device = device;
            RpcType = 1;
            OpType = 1;
            Status = 0;
        }
        /// <summary>
        /// 生成消息载荷，默认实现 可重写
        /// </summary>
        /// <returns></returns>
        public virtual byte[] GetPayload()
        {
            var blockData = CreateBlock();
            var blockHeader = CreateRpcBlockHeader(blockData.Length);
            var header = CreateRpcHeader(blockHeader.Length + blockData.Length);
            return [
                ..Frame,
                ..header,
                ..blockHeader,
                ..blockData
                ];
        }
        /// <summary>
        /// 生成block 可重写
        /// </summary>
        /// <returns></returns>
        public virtual byte[] CreateBlock()
        {
            var data = CreateBlockData();
            if (data.Length > 0)
            {
                return [
                ..BitConverter.GetBytes(OptionType).Reverse(),
                ..BitConverter.GetBytes(data.Length).Reverse(),
                ..data
                ];
            }
            else
            {
                return [];
            }
            
        }
        /// <summary>
        /// 生成消息块的方法，每个子类必须实现
        /// </summary>
        /// <returns></returns>
        public abstract byte[] CreateBlockData();
        /// <summary>
        /// 报文转化为结果的方法 每个子类必须实现
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public abstract T ConvertData2Result(byte[] bytes);
        /// <summary>
        /// 判断是否是本次返回的报文
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public virtual bool IsResponse(byte[] bytes)
        {
            if (bytes.Length < 60)
            {
                return false;
            }
            var reciveUUID = bytes[28..44];
            return BitConverter.ToString(UUID) == BitConverter.ToString(reciveUUID);
        }
        /// <summary>
        /// 接收报文的过滤器名称
        /// </summary>
        public virtual string Filter { get; } = "ether proto 0xf1f1";

        public virtual Task<List<T>> GetCommunicationResult()
        {
            return Task.Run(() =>
            {
                var list = new List<T>();
                if (IsAutoControlDevice)
                {
                    Device.Open();
                    //Device.Filter = Filter;
                }
                var exitEvent = new ManualResetEvent(false);
                var header = GetEthernetHeader(Device.GetDeviceMacAddr()!, DestinationMac);
                var ethernetPacket = new EthernetPacket(new ByteArraySegment(header));
                var connectData = GetPayload();
                ethernetPacket.PayloadData = connectData;
                int i = 0;
                Device.OnPacketArrival += (sender, args) =>
                {
                    var p = args.GetPacket();
                    if (IsResponse(p.Data))
                    {
                        i++;
                        if (i >= ReciveBreak)
                        {
                            exitEvent.Set();
                        }
                        T result = ConvertData2Result(p.Data);
                        list.Add(result);
                    }
                };
                Device.StartCapture();
                Device.SendPacket(ethernetPacket);
                exitEvent.WaitOne(WaitMillisecond);
                if (IsAutoControlDevice)
                {
                    Device.StopCapture();
                    Device.Close();
                }
                return list;
            });
        }
        /// <summary>
        /// 创建发送数据包头
        /// </summary>
        /// <param name="srcMac"></param>
        /// <param name="desMac"></param>
        /// <returns></returns>
        protected virtual byte[] GetEthernetHeader(PhysicalAddress srcMac, PhysicalAddress desMac)
        {
            var srcByte = srcMac.GetAddressBytes();
            var desByte = desMac.GetAddressBytes();
            return [
                ..desByte,
                ..srcByte,
                ..CustomerType
                ];
            //var header = new byte[srcByte.Length + desByte.Length + CustomerType.Length];
            //for (int i = 0; i < desByte.Length; i++)
            //{
            //    header[i] = desByte[i];
            //}
            //for (int i = 0; i < srcByte.Length; i++)
            //{
            //    header[i + desByte.Length] = srcByte[i];
            //}
            //for (int i = 0; i < CustomerType.Length; i++)
            //{
            //    header[i + desByte.Length + srcByte.Length] = CustomerType[i];
            //}
            //return header;
        }
        protected virtual byte[] CreateRpcHeader(int length)
        {
            byte[] data = [
                ..BitConverter.GetBytes(Version).Reverse(),
                ..BitConverter .GetBytes(RpcType).Reverse(),
                ..BitConverter.GetBytes(OpType).Reverse(),
                ..BitConverter.GetBytes(RESL).Reverse(),
                ..new byte[]{FrgFlg},
                ..new byte[]{LastFrgElg},
                ..new byte[]{NoFackFlg},
                ..new byte[]{RES2},
                ..UUID,
                ..BitConverter.GetBytes(SeqId).Reverse(),
                ..BitConverter.GetBytes(length).Reverse(),
                ..BitConverter.GetBytes(FrqNum).Reverse(),
                ..BitConverter.GetBytes(Status).Reverse(),
                ..Res3];
            return data;
        }
        protected virtual byte[] CreateRpcBlockHeader(int length)
        {
            byte[] data = [
                ..BitConverter.GetBytes(DcpType).Reverse(),
                ..BitConverter.GetBytes(OperationId).Reverse(),
                ..BitConverter.GetBytes(SeqId).Reverse(),
                ..BitConverter.GetBytes(0).Reverse(),
                ..BitConverter.GetBytes(length).Reverse()
                ];
            return data;
        }
        /// <summary>
        /// 重试方法
        /// </summary>
        /// <param name="exceFunc">需要执行的异步方法</param>
        /// <param name="successCondition">判断方法执行成功的条件(方法执行失败不能抛异常)</param>
        /// <param name="retryTimes">重试次数</param>
        /// <returns></returns>
        protected async Task<List<T>> RetryFunction(Func<Task<List<T>>> exceFunc,Func<List<T>,bool> successCondition,int retryTimes = 2)
        {
            List<T> result= [];
            int retry = 0;
            while (retry < retryTimes)
            {
                result = await exceFunc.Invoke();
                if (successCondition.Invoke(result))
                {
                    break;
                }
                else
                {
                    retry++;
                }
            }
            return result;
        }

    }
}
